package cn.heyige.backend.facade;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import cn.heyige.backend.entity.UserDO;
import cn.heyige.backend.entity.UserQuotaDO;
import cn.heyige.backend.exception.BusinessException;
import cn.heyige.backend.exception.ErrorCode;
import cn.heyige.backend.mapper.UserMapper;
import cn.heyige.backend.mapper.UserQuotaMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;

@Slf4j
@Service
@RequiredArgsConstructor
public class UserQuotaFacade {

    private final UserQuotaMapper userQuotaMapper;
    private final UserMapper userMapper;

    /**
     * 检查用户配额是否足够
     *
     * @param userId 用户ID
     * @param tokens 需要的token数量
     * @return 是否足够
     */
    public boolean checkQuota(Long userId, Integer tokens) {
        UserQuotaDO userQuotaDO = this.getUserQuota(userId);
        // 检查是否是VIP用户
        UserDO userDO = userMapper.selectById(userId);
        if (userDO == null) {
            throw new BusinessException(ErrorCode.USER_NOT_FOUND);
        }
        // VIP用户不限制配额
        if ("VIP".equals(userDO.getMembershipType()) && userDO.getMembershipExpiry().isAfter(LocalDateTime.now())) {
            return true;
        }
        // 检查配额是否足够
        return userQuotaDO.getRemainingQuota() >= tokens;
    }

    /**
     * 扣除用户配额
     *
     * @param userId 用户ID
     * @param tokens 扣除的token数量
     */
    @Transactional(rollbackFor = Exception.class)
    public void deductQuota(Long userId, Integer tokens) {
        UserQuotaDO userQuotaDO = this.getUserQuota(userId);

        // 检查是否是VIP用户
        UserDO userDO = userMapper.selectById(userId);
        if (null == userDO) {
            throw new BusinessException(ErrorCode.USER_NOT_FOUND);
        }

        // VIP用户不扣除配额
        if ("VIP".equals(userDO.getMembershipType()) && userDO.getMembershipExpiry().isAfter(LocalDateTime.now())) {
            return;
        }
        // 检查配额是否足够
        if (userQuotaDO.getRemainingQuota() < tokens) {
            throw new BusinessException(ErrorCode.USER_QUOTA_INSUFFICIENT);
        }
        // 扣除配额
        userQuotaDO.setRemainingQuota(userQuotaDO.getRemainingQuota() - tokens);
        userQuotaDO.setUsedQuota(userQuotaDO.getUsedQuota() + tokens);
        userQuotaDO.setLastUsedTime(LocalDateTime.now());
        userQuotaMapper.insert(userQuotaDO);
        log.info("用户 {} 扣除配额 {}，剩余配额 {}", userId, tokens, userQuotaDO.getRemainingQuota());
    }

    /**
     * 增加用户配额
     *
     * @param userId 用户ID
     * @param tokens 增加的token数量
     */
    @Transactional(rollbackFor = Exception.class)
    public void addQuota(Long userId, Integer tokens) {
        UserQuotaDO userQuotaDO = this.getUserQuota(userId);
        userQuotaDO.setRemainingQuota(userQuotaDO.getRemainingQuota() + tokens);
        userQuotaMapper.insert(userQuotaDO);
        log.info("用户 {} 增加配额 {}，剩余配额 {}", userId, tokens, userQuotaDO.getRemainingQuota());
    }

    /**
     * 获取用户配额信息
     *
     * @param userId 用户ID
     * @return 用户配额信息
     */
    public UserQuotaDO getUserQuota(Long userId) {
        UserQuotaDO userQuotaDO = userQuotaMapper.selectOne(new LambdaQueryWrapper<UserQuotaDO>().eq(UserQuotaDO::getUserId, userId));
        if (userQuotaDO == null) {
            throw new BusinessException(ErrorCode.USER_QUOTA_NOT_EXISTS);
        }
        return userQuotaDO;
    }

    /**
     * 重置用户配额（每日重置）
     *
     * @param userId 用户ID
     */
    @Transactional(rollbackFor = Exception.class)
    public void resetDailyQuota(Long userId) {
        UserQuotaDO userQuotaDO = this.getUserQuota(userId);
        userQuotaDO.setRemainingQuota(userQuotaDO.getTotalQuota());
        userQuotaMapper.insert(userQuotaDO);
        log.info("用户 {} 每日配额已重置", userId);
    }

    /**
     * 初始化用户配额
     *
     * @param userId     用户ID
     * @param totalQuota 总配额
     */
    @Transactional(rollbackFor = Exception.class)
    public void initializeQuota(Integer userId, Integer totalQuota) {
        UserQuotaDO userQuotaDO = new UserQuotaDO();
        userQuotaDO.setUserId(userId);
        userQuotaDO.setTotalQuota(totalQuota);
        userQuotaDO.setRemainingQuota(totalQuota);
        userQuotaDO.setUsedQuota(0);
        userQuotaMapper.insert(userQuotaDO);
        log.info("用户 {} 配额已初始化，总配额 {}", userId, totalQuota);
    }

    /**
     * 更新用户总配额
     *
     * @param userId     用户ID
     * @param totalQuota 新的总配额
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateTotalQuota(Long userId, Integer totalQuota) {
        UserQuotaDO userQuotaDO = this.getUserQuota(userId);
        // 计算差值
        int diff = totalQuota - userQuotaDO.getTotalQuota();
        userQuotaDO.setTotalQuota(totalQuota);
        userQuotaDO.setRemainingQuota(userQuotaDO.getRemainingQuota() + diff);
        userQuotaMapper.insert(userQuotaDO);
        log.info("用户 {} 总配额已更新为 {}，剩余配额 {}", userId, totalQuota, userQuotaDO.getRemainingQuota());
    }

}